package repository

import (
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEnv"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/FileName"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/FileText"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/OS"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Slice"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEnv"
	"go-fox-edge-kernel-manager/component"
	"io/ioutil"
	"strings"
)

type repoLocalAppConfService struct {
}

func (e *repoLocalAppConfService) GetConfFileInfoList() []map[string]interface{} {
	result := make([]map[string]interface{}, 0)

	result = Slice.Append(result, e.readConfFileType("kernel"))
	result = Slice.Append(result, e.readConfFileType("system"))
	result = Slice.Append(result, e.readConfFileType("service"))

	return result
}

func (e *repoLocalAppConfService) readConfFileType(appType string) []map[string]interface{} {
	result := make([]map[string]interface{}, 0)

	shellDir := FileName.GetOsFilePath(commEnv.Service.WorkDir + "/shell/" + appType)
	if !FileName.IsDir(shellDir) {
		return result
	}

	// 获得目录下的文件
	dirs, err := FileName.List(shellDir)
	if err != nil {
		return result
	}

	for _, appName := range dirs {
		// 检测：是否为目录
		if !FileName.IsDir(FileName.GetOsFilePath(shellDir + "/" + appName)) {
			continue
		}

		// 读取模块的service.conf信息
		data, err := e.readConfFileTypeName(appType, appName)
		if err != nil || data == nil {
			continue
		}

		result = append(result, data)
	}

	return result
}

func (e *repoLocalAppConfService) readConfFileTypeName(appType string, appName string) (map[string]interface{}, error) {
	filePath := FileName.GetOsFilePath(commEnv.Service.WorkDir + "/shell/" + appType + "/" + appName + "/service.conf")
	if !FileName.IsFile(filePath) {
		return nil, errors.New("指定的文件不存在")
	}

	data, err := e.readConfFile(filePath)
	if err != nil {
		return nil, err
	}
	if appType != data["appType"] {
		return nil, errors.New("service.conf文件种的appType与模块的service不匹配！")
	}

	return data, nil
}

func (e *repoLocalAppConfService) readConfFile(filePath string) (map[string]interface{}, error) {
	lineList, err := FileText.ReadTextFileLines(filePath)
	if err != nil {
		return nil, err
	}
	if len(lineList) == 0 {
		return nil, errors.New("读取文件内容失败")
	}

	// 读取文件内容
	appEngine := e.getParam(lineList, "appEngine")
	appType := e.getParam(lineList, "appType")
	appName := e.getParam(lineList, "appName")
	jarName := e.getParam(lineList, "jarName")
	loaderName := e.getParam(lineList, "loaderName")
	springParam := e.getParam(lineList, "springParam")
	confFiles := e.getParam(lineList, "confFiles")
	pyName := e.getParam(lineList, "pyName")
	pythonParam := e.getParam(lineList, "pythonParam")
	nativeName := e.getParam(lineList, "nativeName")
	nativeParam := e.getParam(lineList, "nativeParam")

	// 验证数据
	if Method.HasEmpty(appType) || Method.HasEmpty(appName) {
		return nil, errors.New("配置文件内容，缺失配置项: appType, appName")
	}

	// 检测：如果没有填写，就是旧版本的conf文件，那么默认为java程序
	if Method.HasEmpty(appEngine) {
		appEngine = "java"
	}

	data := make(map[string]interface{})
	data["appEngine"] = appEngine
	data["appName"] = appName
	data["appType"] = appType
	data["loaderName"] = loaderName

	if appEngine == "java" {
		// java程序：必填项目jarName
		if Method.HasEmpty(jarName) {
			return nil, errors.New("配置文件内容，缺失配置项: jarName")
		}
		pathName := LocalPathName.getPathName4LocalBin2MainFile(appType, appName, jarName)

		data["pathName"] = pathName
		data["fileName"] = jarName
		data["userParam"] = springParam
	} else if appEngine == "python" || appEngine == "python3" {
		// python程序：必填项目pyName
		if Method.HasEmpty(pyName) {
			return nil, errors.New("配置文件内容，缺失配置项: pyName")
		}
		pathName := LocalPathName.getPathName4LocalBin2MainFile(appType, appName, pyName)

		data["pathName"] = pathName
		data["fileName"] = pyName
		data["userParam"] = pythonParam
	} else if appEngine == "native" {
		// native程序：必填项目nativeName, nativeParam
		if Method.HasEmpty(nativeName, nativeParam) {
			return nil, errors.New("配置文件内容，缺失配置项: nativeName, nativeParam")
		}
		pathName := LocalPathName.getPathName4LocalBin2MainFile(appType, appName, nativeName)

		data["pathName"] = pathName
		data["fileName"] = nativeName
		data["userParam"] = nativeParam
	} else {
		return nil, errors.New("配置文件内容，尚未支持的程序类型: " + appEngine)
	}

	// conf文件列表
	list := make([]string, 0)
	if !Method.HasEmpty() {
		confFileArr := strings.Split(confFiles, ";")
		for _, confFile := range confFileArr {
			if confFile == "" {
				continue
			}

			list = append(list, confFile)
		}
	}

	data["confFiles"] = list

	return data, nil
}

func (e *repoLocalAppConfService) SaveConf(filePath string, data map[string]interface{}) error {
	// 读取文件内容
	appEngine := Map.GetString(data, "appEngine", "")
	appType := Map.GetString(data, "appType", "")
	appName := Map.GetString(data, "appName", "")
	fileName := Map.GetString(data, "fileName", "")
	loaderName := Map.GetString(data, "loaderName", "")
	userParam := Map.GetString(data, "userParam", "")
	confFiles := Map.GetSlice(data, "confFiles", nil)

	// 验证数据
	if Method.HasEmpty(appType, appName, fileName) {
		return errors.New("缺失配置参数：appType, appName, fileName")
	}

	sb := ""
	sb += "appEngine=" + appEngine + "\r\n"
	sb += "appType=" + appType + "\r\n"
	sb += "appName=" + appName + "\r\n"

	if appEngine == "java" {
		sb += "jarName=" + fileName + "\r\n"
		sb += "springParam=\"" + userParam + "\"" + "\r\n"
		sb += "loaderName=" + loaderName + "\r\n"
		sb += "confFiles=\""
		for _, line := range confFiles {
			sb += line.(string) + ";"
		}
		sb += "\""
	}
	if appEngine == "python" || appEngine == "python3" {
		sb += "pyName=" + fileName + "\r\n"
		sb += "pythonParam=\"" + userParam + "\"" + "\r\n"
	}
	if appEngine == "native" {
		sb += "nativeName=" + fileName + "\r\n"
		sb += "nativeParam=\"" + userParam + "\"" + "\r\n"
	}

	sb += "\r\n"

	// 保存数据到文件
	err := ioutil.WriteFile(filePath, []byte(sb), 0644)
	if err != nil {
		return err
	}

	return nil
}

func (e *repoLocalAppConfService) getParam(lineList []string, paramName string) string {
	for _, line := range lineList {
		if !strings.HasPrefix(line, paramName+"=") {
			continue
		}

		value := line[len(paramName)+1:]
		if strings.HasPrefix(value, "\"") {
			value = value[1:]
		}
		if strings.HasSuffix(value, "\"") {
			value = value[:len(value)-1]
		}

		return value
	}

	return ""
}

func (e *repoLocalAppConfService) Filter(list []map[string]interface{}) ([]map[string]interface{}, error) {
	// 过滤掉非当前版本的gateway和manager
	list, err := e.FilterModelList(list)
	if err != nil {
		return nil, err
	}

	// 只保留原生代码类型
	list, err = e.OnlyNative(list)
	if err != nil {
		return nil, err
	}

	// 剔除跟操作系统和CPU架构不匹配的数据
	list, err = e.FilterOSTypeAndCpuArch(list)
	if err != nil {
		return nil, err
	}

	return list, nil
}

func (e *repoLocalAppConfService) OnlyNative(appList []map[string]interface{}) ([]map[string]interface{}, error) {
	kernelEnableConfig, err := component.ManageConfigService.GetConfigValueThis("kernelEnableConfig")
	if err != nil {
		return nil, err
	}

	onlyNative := Map.GetBool(kernelEnableConfig, "onlyNative", false)

	result := make([]map[string]interface{}, 0)
	for _, data := range appList {
		modelName := Map.GetString(data, "modelName", "")

		if true == onlyNative {
			if strings.Contains(strings.ToLower(modelName), "native") {
				result = append(result, data)
			}
		} else {
			result = append(result, data)
		}
	}

	return result, nil
}

func (e *repoLocalAppConfService) FilterOSTypeAndCpuArch(appList []map[string]interface{}) ([]map[string]interface{}, error) {
	edgeOsType := OS.Type.GetOSType()
	edgeCpuArch := edgeEnv.GetARCH()

	// 开发环节下，不进行这个项目的过滤
	if edgeEnv.IsDevEnv() {
		return appList, nil
	}

	result := make([]map[string]interface{}, 0)
	for _, data := range appList {
		osType := Map.GetString(data, "osType", "")
		cpuArch := Map.GetString(data, "cpuArch", "")

		// 检查类型是否匹配
		if osType != "all" && osType != edgeOsType {
			continue
		}
		if cpuArch != "all" && cpuArch != edgeCpuArch {
			continue
		}

		result = append(result, data)
	}

	return result, nil
}

func (e *repoLocalAppConfService) FilterModelList(appList []map[string]interface{}) ([]map[string]interface{}, error) {
	result := make([]map[string]interface{}, 0)
	for _, data := range appList {
		// 需要的appType/appName，在component/modelName字段之中
		appType := Map.GetString(data, "component", "")
		appName := Map.GetString(data, "modelName", "")

		if edgeEnv.Name.IsDisable(appType, appName) {
			continue
		}

		result = append(result, data)
	}

	return result, nil
}

func (e *repoLocalAppConfService) FilterAppConfFile(appList []map[string]interface{}) ([]map[string]interface{}, error) {
	result := make([]map[string]interface{}, 0)
	for _, data := range appList {
		// 需要的appType/appName，在component/modelName字段之中
		appType := Map.GetString(data, "appType", "")
		appName := Map.GetString(data, "appName", "")

		if edgeEnv.Name.IsDisable(appType, appName) {
			continue
		}

		result = append(result, data)
	}

	return result, nil
}
